﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace SystemHelperLibrary.Ini
{
	public class MyMultiMap<Key, Value> : IDisposable, IEnumerable<KeyValuePair<Key, List<Value>>>
		where Key : IComparable<Key>
		where Value : IComparable<Value>
	{

		private Dictionary<Key, List<Value>> m_dictionary;
		bool disposing = false;

		private static object syncLock = new object();

		public MyMultiMap()
		{
			m_dictionary = new Dictionary<Key, List<Value>>();
		}

		public void Dispose()
		{
			Dispose(true);
		}

		private void Dispose(bool p)
		{
			lock (syncLock)
			{
				disposing = p;
				if (!disposing)
				{
					if (m_dictionary.Keys.Count > 0)
					{
						foreach (Key k in m_dictionary.Keys)
						{
							if (m_dictionary[k].Count > 0)
							{
								m_dictionary[k].Clear();
							}
						}
					}
					m_dictionary.Clear();

					if (disposing)
					{
						m_dictionary = null;
						syncLock = null;
						GC.SuppressFinalize(this);
						GC.Collect();
					}
				}

			}
		}

		public void ClearAll()
		{
			this.Dispose(false);
		}

		public void Add(Key key, Value val)
		{
			lock (syncLock)
			{
				if (m_dictionary.ContainsKey(key))
				{
					m_dictionary[key].Add(val);
				}
				else
				{
					List<Value> valData = new List<Value>();
					valData.Add(val);
					m_dictionary.Add(key, valData);
				}
			}
		}

		public void AddWithoutValue(Key key)
		{
			lock (syncLock)
			{
				if (m_dictionary.ContainsKey(key))
				{
					return;
				}
				else
				{
					List<Value> valData = new List<Value>();
					m_dictionary.Add(key, valData);
				}
			}
		}

		public int Count
		{
			get
			{
				lock (syncLock)
				{
					return m_dictionary.Count;
				}
			}
		}

		public List<Value> GetData(Key key)
		{
			lock (syncLock)
			{
				if (m_dictionary.ContainsKey(key))
				{
					return m_dictionary[key];
				}
			}
			return new List<Value>();
		}

		public void EditValue(Key key, Value oldValue, Value newValue)
		{
			lock (syncLock)
			{
				if (m_dictionary.ContainsKey(key))
				{
					if (m_dictionary[key].Contains(oldValue))
					{
						for (int i = 0; i < m_dictionary[key].Count; i++)
						{
							if (m_dictionary[key][i].Equals(oldValue))
							{
								m_dictionary[key][i] = newValue;
								break;
							}
						}
					}
				}
			}
		}

		public void ClearValues(Key key)
		{
			lock (syncLock)
			{
				if (m_dictionary.ContainsKey(key))
				{
					m_dictionary[key].Clear();
				}
			}
		}

		public IEnumerator<KeyValuePair<Key, List<Value>>> GetEnumerator()
		{
			return m_dictionary.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return m_dictionary.GetEnumerator();
		}
	}

	public class IniReader
	{
		private MyMultiMap<string, string> m_container;
		private Dictionary<string, Dictionary<string, string>> m_dictContainer;

		protected StreamReader m_streamReader;
		protected string m_fileName;
		string m_data = string.Empty;

		public IniReader()
		{
			m_container = new MyMultiMap<string, string>();
			m_dictContainer = new Dictionary<string, Dictionary<string, string>>();
			m_fileName = string.Empty;
		}

		public IniReader(string filePath)
		{
			m_container = new MyMultiMap<string, string>();
			m_dictContainer = new Dictionary<string, Dictionary<string, string>>();
			m_fileName = filePath;
		}

		public void Load()
		{
			if (!File.Exists(m_fileName))
			{
				using (StreamWriter sw = new StreamWriter(m_fileName))
				{
					sw.WriteLine("//Ini file settings");
					sw.WriteLine("[Data]");
					sw.WriteLine("Value1=Data1");
					sw.WriteLine("Value2=Data2");
					sw.WriteLine("Value3=Data3");
				}

			}
			m_streamReader = new StreamReader(this.m_fileName);

			this.m_dictContainer.Clear();
			this.m_container.ClearAll();

			string data = string.Empty;
			string key = string.Empty;

			while ((data = m_streamReader.ReadLine()) != null)
			{
				if (data.StartsWith("//") || data.StartsWith("\\") || data.StartsWith("--") || string.IsNullOrEmpty(data))
					continue;

				if (data.StartsWith("[") && data.EndsWith("]") && data.Length > 2)
				{
					key = data.Replace("[", "").Replace("]", "").Trim();
					m_container.AddWithoutValue(key);

					m_dictContainer.Add(key, new Dictionary<string, string>());
					continue;
				}
				else
				{
					int i;
					if ((i = data.IndexOf('=')) > 0)
					{
						string par = data.Substring(0, i);
						int j = data.Length - 1 - i;
						string val = j > 0 ? data.Substring(i + 1, j) : "";

						if (m_dictContainer.ContainsKey(key))
						{
							m_dictContainer[key].Add(par, val);
						}

						m_container.Add(key, data.Trim());
					}
				}
			}

			m_streamReader.Close();
		}

		public MyMultiMap<string, string> Data
		{
			get
			{
				return this.m_container;
			}

			private set
			{
				m_container = value;
			}
		}

		public Dictionary<string, Dictionary<string, string>> Data2
		{
			get
			{
				return m_dictContainer;
			}
		}


		public List<string> GetKeys()
		{
			if (m_container.Count > 0)
			{
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, List<string>> item in m_container)
				{
					list.Add(item.Key);
				}
				return list;
			}

			return new List<string>();
		}

		public List<string> GetValuesForKey(string key)
		{
			bool finded = false;

			if (m_container.Count > 0)
			{
				List<string> list = new List<string>();
				foreach (KeyValuePair<string, List<string>> item in m_container)
				{
					if (item.Key.ToLower() == key.ToLower())
					{
						finded = true;
						foreach (string s in item.Value)
						{
							list.Add(s);
						}
					}

					if (finded)
						break;
				}
				return list;
			}

			return new List<string>();
		}

	}
}
